<template>
  <div class="chat-dialog" @drop.prevent="$message.info('拖动到输入框可以直接发送文件哦')" @dragover.prevent>
    <scroll-box class="scroll-box" listenHeight ref="scrollBox" :topDisabled="topDisabled" @touchTop="getChatList(chatList[0].updatedAt)">
      <loading v-if="!topDisabled && chatList.length >= 30"></loading>
      <component :is="item.component" v-for="item in chatList" :key="item.updateAt" :chat="item" :content="item.content"></component>
    </scroll-box>
  </div>
</template>

<script>
import { api_getChatList } from '@/api/chat'
import userItem from './children/userItem.vue'
import TalkerItem from './children/talkerItem.vue'
import NotificationTag from './children/NotificationTag'
import ScrollBox from '@/components/ScrollBox.vue'
import Loading from '@/components/Loading.vue'
export default {
  components: { userItem, TalkerItem, ScrollBox, Loading, NotificationTag },
  name: 'chat-dialog',
  props: {
    // 当前的sessionId
    sessionId: Number,
  },
  data () {
    return {
      chatList: [],
      // 禁止触顶
      topDisabled: false,
      // 取消请求聊天列表的方法
      cancelChatListFunc: null,
      timeTagFunc: this.createTimeTag()
    }
  },
  created () {
    // 监听输入框发送的消息
    this.$bus.$on('sendMsg', this.sendMsg)
    // 接收其它用户发送的消息
    this.$bus.$on('chat', this.receiveChat)
    // 发送消息成功
    this.$bus.$on('sendMsgSuccess', this.sendMsgSuccess)
    // 发送消息失败
    this.$bus.$on('sendMsgFail', this.sendMsgFail)

    // 第一次创建时直接请求聊天数据
    this.getChatList()
  },

  beforeDestroy () {
    this.$bus.$off('sendMsg', this.sendMsg)
    this.$bus.$off('chat', this.receiveChat)
    this.$bus.$off('sendMsgSuccess', this.sendMsgSuccess)
    this.$bus.$on('sendMsgFail')

    this.cancelChatListFunc()
  },

  methods: {
    // 请求
    // 请求聊天记录
    getChatList (lastTime) {
      this.topDisabled = true;
      api_getChatList({ sessionId: this.$store.state.currentSession.sessionId, lastTime }, this).then(res => {
        if (res.data.code === 200) {
          // this.chatList = res.data.list
          let arr = this.insertTimeTag(res.data.list)

          if (!lastTime) {
            this.chatList.unshift(...arr)
            // 没传时间，则是第一次获取聊天记录，滚动到底部
            this.scrollToFunc('instant')
          } else {
            this.$refs.scrollBox.keepHeight(() => {
              this.chatList.unshift(...arr)
            })
          }

          // 聊天记录一次请求30条，小于30条说明没有更多聊天数据了
          this.topDisabled = arr.length < 30

        }
      })
    },

    // 输入框发送消息的回调
    sendMsg (chatItem) {
      let timeTag = this.timeTagFunc(chatItem, this.chatList[this.chatList.length - 1])
      if (timeTag) this.chatList.push(timeTag)
      chatItem.component = 'user-item'
      this.chatList.push(chatItem)
      // 自己发消息，直接滚到底部
      // 图片加载需要一定时间, 监听img的onload事件是更好的做法, 但是这里不想弄了, 定时器凑合一下
      let timer = setTimeout(() => {
        this.scrollToFunc()
        clearTimeout(timer)
        timer = null;
      }, 50)
    },

    // 接收别的用户发送的消息
    receiveChat (msg) {
      // console.log(msg);
      if (msg.type == 4) {
        msg.component = 'notification-tag'
      } else {
        let timeTag = this.timeTagFunc(msg, this.chatList[this.chatList.length - 1])
        if (timeTag) this.chatList.push(timeTag)
        msg.component = msg.talkerId == this.$store.state.currentSession.receiverId ? 'talker-item' : 'user-item'
      }
      this.chatList.push(msg)
      // 判断当前是否离底，再进行滚动
      if (this.$refs.scrollBox.getIsBottom(100)) {
        this.scrollToFunc()
      }
    },

    // 消息发送成功后的回调
    sendMsgSuccess (msg) {
      // 倒序遍历数组，因为刚发送的消息一般接近底部
      for (let i = this.chatList.length - 1; i >= 0; i--) {
        if (this.chatList[i].uuid === msg.uuid) {
          // this.chatList[i] = msg
          this.chatList[i].updatedAt = msg.updatedAt
          this.chatList[i].status = 'success'
          // console.log(this.chatList[i]);
          if (this.chatList[i].type === 1) {
            this.chatList[i].content = msg.content
          }
          break
        }
      }
    },

    // 发送消息失败的回调
    sendMsgFail (msg) {
      // 倒序遍历数组，因为刚发送的消息一般接近底部
      for (let i = this.chatList.length - 1; i >= 0; i--) {
        if (this.chatList[i].uuid === msg.uuid) {
          // this.chatList[i] = msg
          // this.chatList[i].updatedAt = msg.updatedAt
          this.chatList[i].status = 'fail'
          // console.log(this.chatList[i]);
          // if (this.chatList[i].type === 1) {
          //   this.chatList[i].content = msg.content
          // }
          break
        }
      }
    },

    // 聊天框滚动到底部
    scrollToFunc (behavior) {
      this.$nextTick(() => {
        if (!this.$refs.scrollBox) return
        this.$refs.scrollBox.scrollToFunc(behavior)
      })
    },

    // 根据消息时间插入时间节点标签
    insertTimeTag (chatList) {
      let arr = []
      let userId = this.$store.state.userInfo.id;
      // 当天0点时间戳
      // let today = this.$moment().startOf('day').valueOf()
      // let thisWeek = this.$moment().week(this.$moment().week() - 1).startOf('week').valueOf() + 86400000
      // console.log(today, thisWeek);

      chatList.forEach((item, index, list) => {
        // 通知
        if (item.type == 4) {
          item['component'] = 'notification-tag'
          // 删除好友通知
          if (item.content == "deleteFriend") {
            if (item.senderId == userId) {
              item.content = '您已与对方解除好友关系'
            } else {
              item.content = '对方已与您解除好友关系'
            }
          }
        } else {
          // 其它类型信息
          if (item.senderId == userId) {
            item['component'] = 'user-item'
          } else {
            item['component'] = 'talker-item'
          }
        }
        arr.unshift(item);

        let timeTag = index < list.length - 1 && this.timeTagFunc(item, list[index + 1])
        if (timeTag) arr.unshift(timeTag)
      })
      return arr;
    },

    // 将本日和本周时间戳闭包
    createTimeTag () {
      // 当天0点时间戳
      let today = this.$moment().startOf('day').valueOf()
      let thisWeek = this.$moment().week(this.$moment().week() - 1).startOf('week').valueOf() + 86400000

      return function (item1, item2) {
        // 间隔超过5分钟显示时间节点标签
        if (item1.updatedAt - item2.updatedAt > 5 * 60000) {
          let time = null
          if (item1.updatedAt * 1 > today) time = this.$moment(item1.updatedAt * 1).format('HH:mm')
          else if (item1.updatedAt * 1 > thisWeek) time = this.$moment(item1.updatedAt * 1).locale('zh-cn').format('dddd HH:mm')
          else time = this.$moment(item1.updatedAt * 1).format('YYYY年MM月DD日 HH:mm')

          // arr.unshift({ time, component: 'time-tag' })
          return { content: time, component: 'notification-tag' }
        }
      }
    },

  },

  watch: {
    "$store.state.currentSession" () {
      this.chatList = []
      this.cancelChatListFunc('cancelChatListFunc')

      this.getChatList()
    }
  }
}
</script>

<style scoped>
.scroll-box {
  height: calc(100vh - 228.5px);
  overflow-y: scroll;
  padding: 0 25px;
}
</style>